import { api } from "@/api"
import { useAppStore } from "@/stores/app"
import useContactsStore from "@/stores/contacts"
import { typeToValue, valueToType } from "@/utils"
import { decode, encode } from "js-base64"
import Vue from "vue"

const RECONNECT_INTERVAL = 5000; // 重连间隔，单位：毫秒

export class Chat {
  constructor() {
    this.retryCount = 0
    this.heartbeatTimer = null
    this.history = Vue.observable({
      value: {}
    })
  }


  init() {
    clearInterval(this.heartbeatTimer)
    this.appStore = useAppStore()
    this.contactsStore = useContactsStore()
    this.ws = new WebSocket(process.env.VUE_APP_WS_URL)
    this.ws.addEventListener('message', this.receiveMessage.bind(this))
    this.ws.addEventListener('open', () => {
      this.retryCount = 0
      console.log('connect success')
      // 心跳
      this.heartbeatTimer = setInterval(() => {
        this.ws.send('heart')
      }, 3000);
    })
    this.ws.addEventListener('close', (event) => {
      console.log(`connect close: ${event.code}`);
      clearInterval(this.heartbeatTimer)
      // 重新连接
      if (this.retryCount === 0) {
        this.init()
      } else {
        setTimeout(this.init.bind(this), RECONNECT_INTERVAL);
      }
      this.retryCount++
    })
    this.ws.addEventListener('error', (error) => {
      console.log('connect error', error)
    })
  }

  sendMessage({ to, type, msg, fingerPrint, isGroup = false }) {
    const payload = {
      from: this.appStore.userInfo.username,
      to,
      msg,
      content_type: typeToValue(type),
      fingerPrint,
      nick_name: this.appStore.userInfo.nickname,
      avatar_url: this.appStore.userInfo.avatar,
      type: isGroup ? 1 : 0
    }
    const data = JSON.stringify(payload)
    this.ws.send(encode(data))
    this.pushMessage(to, { ...payload })
    this.createSession(to)
  }

  async loadHistory({ username, page = 0, updateFirst = false }) {
    const { data, count } = await api.chat.history(page, { friendName: username })

    if (!Array.isArray(data) || !data.length) return true

    const originLength = this.history.value[username]?.length ?? 0

    if (updateFirst) {
      data.reverse()
      if (this.history.value[username]) {
        this.history.value[username] = this.history.value[username]?.filter(item => !String(item.id)?.startsWith('local_'))
      }
    }

    data.forEach(item => {
      this.pushMessage(username, item, !updateFirst)
    })

    if (updateFirst && originLength !== this.history.value[username].length) {
      this.appStore.playNotice()
    }

    return this.history.value[username].length >= count || originLength === this.history.value[username].length
  }

  async pushMessage(username, message, shift = false) {
    message = { ...message, id: (Array.isArray(message.msgId) ? message.msgId[0] : message.msgId) ?? message.id ?? `local_${Date.now()}` }
    message.content_type = valueToType(message.content_type)
    if (!String(message.id).startsWith('local_')) message.id = Number(message.id)
    if (this.history.value[username]) {
      if (this.history.value[username].some(item => item.id === message.id)) return
      if (shift) {
        this.history.value[username].unshift(message)
      } else {
        this.history.value[username].push(message)
      }
    } else {
      this.history.value = { ...this.history.value, [username]: Vue.observable([message]) }
    }
  }

  receiveMessage({ data }) {
    console.log('receive message', data)
    if (['ok', '连接成功'].includes(data)) return

    try {
      const msg = JSON.parse(decode(data))
      this.handleMessage(msg)
    } catch (err) {
      console.error(err)
    }
  }

  async handleMessage(msg) {
    // 如果是自己加入的群聊信息
    if (this.contactsStore.groups.some(item => item.GroupId.replace('@TGS#', '@TGS$') === msg.to)) {
      this.pushMessage(msg.to, msg)
      this.appStore.setLastUnread(this.appStore.unread + 1)
      this.appStore.playNotice()
      this.appStore.refreshSessionList(false)
    }
    // 如果是发送给自己的消息
    else if (msg.to === this.appStore.userInfo.username && msg.from !== this.appStore.userInfo.username) {
      this.pushMessage(msg.from, msg)
      this.appStore.setLastUnread(this.appStore.unread + 1)
      this.appStore.playNotice()
      this.appStore.refreshSessionList(false)
    }
  }

  async setRead(username) {
    const msgId = this.history.value[username]?.filter(item => !item.is_read).map(item => item.id) ?? []
    msgId.length > 0 && await api.chat.setRead({ msgId })
  }

  async createSession(target) {
    if (this.appStore.sessionList.length === 0) {
      await this.appStore.refreshSessionList()
    }
    if (this.appStore.sessionList.every(item => item.friend_name !== target)) {
      api.chat.createSession({ friendName: target })
      this.appStore.refreshSessionList()
    }
  }
}

export const chat = new Chat()
